package org.asiainfo.gateway.filter;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.reactor.context.SaReactorSyncHolder;
import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import lombok.extern.slf4j.Slf4j;
import org.asiainfo.common.core.constant.CacheNames;
import org.asiainfo.common.core.constant.HttpStatus;
import org.asiainfo.common.core.utils.StringUtils;
import org.asiainfo.gateway.config.properties.IgnoreWhiteProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.reactive.ServerHttpRequest;

/**
 * sa-token filter 权限拦截器
 *
 * @author dotor-ww
 */
@Configuration
@Slf4j
public class AuthFilter {

    /**
     * 添加过滤器
     *
     * @param ignoreWhite 忽略
     * @return SaReactorFilter
     */
    @Bean
    public SaReactorFilter getSaReactorFilter(IgnoreWhiteProperties ignoreWhite) {
        return new SaReactorFilter()
            // 拦截地址
            .addInclude("/**")
            .addExclude("/favicon.ico", "/actuator", "/actuator/**")
            // 鉴权方法：每次访问进入
            .setAuth(obj -> {
                // 登录校验 -- 拦截所有路由
                SaRouter.match("/**")
                    .notMatch(ignoreWhite.getWhites())
                    .check(r -> {
                        // 检查是否登录 是否有token
                        StpUtil.checkLogin();
                        // 检查 header 与 param 里的 clientId 与 token 里的是否一致
                        ServerHttpRequest request = SaReactorSyncHolder.getContext().getRequest();
                        String headerCid = request.getHeaders().getFirst(CacheNames.CLIENT_KEY);
                        String paramCid = request.getQueryParams().getFirst(CacheNames.CLIENT_KEY);
                        String clientId = StpUtil.getExtra(CacheNames.CLIENT_KEY).toString();
                        if (!StringUtils.equalsAny(clientId, headerCid, paramCid)) {
                            throw NotLoginException.newInstance(
                                StpUtil.getLoginType(),
                                "-100",
                                "客户端ID与Token不匹配",
                                StpUtil.getTokenValue()
                            );
                        }
                    });
            }).setError(e -> {
                if (e instanceof NotLoginException) {
                    return SaResult.error(e.getMessage()).setCode(HttpStatus.UNAUTHORIZED);
                }
                return SaResult.error("认证失败，无法访问系统资源").setCode(HttpStatus.UNAUTHORIZED);
            });
    }
}
